//VirtualCamera.h
//Created 02/06/13
//Created By Daniel Bowler
//
//This will replace our old camera control method and allow us to 
//use a more friendly first person 'flying' camera (One that moves in the direction
//the user is looking). Normally I would implement this as a singleton (Any excuse),
//but for the purposes of this demo application, we wont. Expect version 2.0 of this
//flying camera to be modified in to a singleton with support for n numbers of differnt
//camera with (hopefully) differnt modes supported (FPS, flying, 3rd person perhaps).
//
//Anyway, it is up to the programmer to create one of these per scene - and delete
//the old one in the CloseScene() function. 
//
//Even though this implementation of the camera is identical to the books, it should be
//noted that I studied (3D) virtual cameras extensivly duing my programming 4 (PS3 game)
//module where I implemeneted a first person camera that wouldnt look out of place in any
//FPS game. Alot of the concepts from said study have croped up now so I fully undersand
//how things work in this class (eg, the right vector used to straffe along)
//
// FLOATX   |   XMVECTOR/XMMATRIX
//
//    ----------------> XMLoad...
//
//    <---------------- XMStore...
//
//
//CONTROLS: Mouse/Keyboard : WADS to walk/strafe. Left mouse button + move mouse
//to look around (rotate). 
//
//			360 Controller : Left stick to walk/straffe, right stick to look around
//(rotate)
//
//In addition, SPACE will move to the next scene (As will 'A' on the 360 pad) and ESC
//will quit the application (As will 'START' on the 360 pad). 1-9 on the keyboard
//will be used to toggle features on/off... As of yet, nothing has been done in my
//demo application that requires a toggle when using the 360 pad.
//
//Modified : 07/07/13 - Class now handles a XNA::Frustum object - which describes
//the projection frustum. We will use this in demo 21 when we want to do some
//frustum culling. In addition, a function has been provided that will transform
//a sperate frustum in to an objects local space (You pass in the objects
//world matrix and the function will do the rest) - you can then test
//for an interesection (with a bounding box/whatever) to determin
//if an object should be rendered. 

#pragma once

//Need both for XNAMaths
#include <Windows.h>
#include <xnamath.h>
#include "xnacollision.h"

class VirtualCamera
{
public:
	//Constructor/Destructor.
	VirtualCamera();
	~VirtualCamera();

	//Get/Set world space camera position
	XMVECTOR GetPositionXM()const;
	XMFLOAT3 GetPosition()const;
	void     SetPosition(float x, float y, float z);
	void     SetPosition(XMVECTOR &vec);
	void     SetPosition(XMFLOAT3 &vec);

	//Returns the cameras basic vectors.
	//
	//Right vector used to straffe along. 
	XMVECTOR GetRightXM()const;
	XMFLOAT3 GetRight()const;
	//Up vector,
	XMVECTOR GetUpXM()const;
	XMFLOAT3 GetUp()const;
	//Look vector
	XMVECTOR GetLookXM()const;
	XMFLOAT3 GetLook()const;

	//Sets Look vector manually
	void SetLook(XMFLOAT3 l);

	//Returns frustum properties.
	float GetNearZ()const;
	float GetFarZ()const;
	float GetAspect()const;
	float GetFovY()const;
	float GetFovX()const;

	//Get near and far plane dimensions in view space coordinates
	float GetNearWindowWidth()const;
	float GetNearWindowHeight()const;
	float GetFarWindowWidth()const;
	float GetFarWindowHeight()const;

	//Set frustum properties - the book referes to this as the lens, though
	//I prefer frustum.
	//Should be called each time the window is resized (Ie, OnResize()). 
	void SetFrustumProperties(float fovY, float aspect, float nearZ, float farZ);

	//Define camera space via LookAt params.
	void SetCameraProperties(FXMVECTOR pos, FXMVECTOR target, FXMVECTOR worldUp);
	void SetCameraProperties(const XMFLOAT3& pos, const XMFLOAT3& target, const XMFLOAT3& worldUp);

	//Get view and projection matrix.
	XMMATRIX GetView()const;
	XMFLOAT4X4 GetViewFloat4x4()const;
	XMMATRIX GetProjection()const;
	XMFLOAT4X4 GetProjectionFloat4x4()const;
	XMMATRIX GetViewProjection()const;
	XMFLOAT4X4 GetViewProjectionFloat4x4()const;

	//Strafe/Walk the camera a distance.
	void Strafe(float distance);
	void Walk(float distance);

	//Rotate the camera (pitch/Yaw)
	void AddPitch(float angleXDegrees);
	void AddYaw(float angleYDegrees);

	//Manually set view matrix - used when we have created a reflection view
	//matrix for water rendering.
	void SetView(XMFLOAT4X4 v){view = v;};

	//After modifying camera position/orientation, call to rebuild the view matrix.
	void RebuildViewMatrix();

	//Returns the frustum volume. 
	XNA::Frustum ReturnFrustumVolume(){return frustumVolume;};
	//Returns a frustum volume transformed to local space of a given object - we 
	//use this in Scene 21 as the AABB of the skull is created in local space. (Uses this 
	//cameras view matrix)
	void ReturnFrustumInLocalSpace(XMFLOAT4X4* objectWorld, XNA::Frustum* localSpaceFrustum);

	//Returns the rotations (in degrees) of the camera
	float GetCameraRotationDegreesPitch();
	float GetCameraRotationDegreesYaw();

private:
	//Camera coordinate system with coordinates relative to world space
	XMFLOAT3 position;
	XMFLOAT3 right;
	XMFLOAT3 up;
	XMFLOAT3 look;

	//Store frustum properties.
	float nearZ;
	float farZ;
	float aspect;
	float fovY;
	float nearWindowHeight;
	float farWindowHeight;

	//Store view/projeciton matricies.
	XMFLOAT4X4 view;
	XMFLOAT4X4 proj;

	//Appended when we add pitch and yaw.
	float rotationsX;
	float rotationsY;

	//Store frustum volume
	XNA::Frustum frustumVolume;
};